/// @NOTE: this file is included from Vector.hpp, IN cvMath:: namespace.

// ctors
template<typename T> Vec2<T>::Vec2() : x(0), y(0) {}
template<typename T> Vec2<T>::Vec2(T i, T j) : x(i), y(j) {}
//template<typename T> Vec2<T>::Vec2(const Vec2<T> &copy) : x(copy.x), y(copy.y) {}
template<typename T> template<typename J> Vec2<T>::Vec2(const Vec2<J> &copy) : x(copy.x), y(copy.y) {}

/// Assing
template<typename T> Vec2<T>& Vec2<T>::operator=	(const Vec2<T> &copy)
{ 	x = copy.x;
	y = copy.y;
	return *this;
}


/// Operators
template<typename T> Vec2<T> operator-	(const Vec2<T> &leftVec)	{ return Vec2<T>(-leftVec.x, -leftVec.y); }
template<typename T> Vec2<T> operator+	(const Vec2<T> &leftVec, const Vec2<T> &rightVec)	{ return Vec2<T>(leftVec.x + rightVec.x, leftVec.y + rightVec.y); }
template<typename T> Vec2<T> operator-	(const Vec2<T> &leftVec, const Vec2<T> &rightVec)	{ return Vec2<T>(leftVec.x - rightVec.x, leftVec.y - rightVec.y); }
template<typename T> Vec2<T> operator*	(const Vec2<T> &leftVec, const T realVal)	{ return Vec2<T>(leftVec.x * realVal, leftVec.y * realVal); }
template<typename T> Vec2<T> operator/	(const Vec2<T> &leftVec, const T realVal)	{ return Vec2<T>(leftVec.x / realVal, leftVec.y / realVal); }
template<typename T> Vec2<T> operator*	(const Vec2<T> &leftVec, const Vec2<T> &rightVec)	{ return Vec2<T>(leftVec.x * rightVec.x, leftVec.y * rightVec.y); }
template<typename T> Vec2<T> operator/	(const Vec2<T> &leftVec, const Vec2<T> &rightVec)	{ return Vec2<T>(leftVec.x / rightVec.y, leftVec.y / rightVec.y); }

/// Assingment operators
template<typename T> Vec2<T>& operator+=	(Vec2<T> &leftVec, const Vec2<T> &rightVec)
{	leftVec.x += rightVec.x;
	leftVec.y += rightVec.y;
	return leftVec;
}

template<typename T> Vec2<T>& operator-=	(Vec2<T> &leftVec, const Vec2<T> &rightVec)
{	leftVec.x -= rightVec.x;
	leftVec.y -= rightVec.y;
	return leftVec;
}

template<typename T> Vec2<T>& operator*=	(Vec2<T> &leftVec, const T realVal)
{	leftVec.x *= realVal;
	leftVec.y *= realVal;
	return leftVec;
}

template<typename T> Vec2<T>& operator/=	(Vec2<T> &leftVec, const T realVal)
{	leftVec.x /= realVal;
	leftVec.y /= realVal;
	return leftVec;
}

template<typename T> bool equals(const Vec2<float> &leftVec, const Vec2<float> &rightVec, const T threshold)
{	T diffX = leftVec.x - rightVec.x;
	T diffY = leftVec.y - rightVec.y;
	return (diffX*diffX + diffY*diffY < threshold);
}

template<typename T> Vec2<T>& operator*=	(Vec2<T> &leftVec, const Vec2<T> &rightVec)
{	leftVec.x *= rightVec.x;
	leftVec.y *= rightVec.y;
	return leftVec;
}

template<typename T> Vec2<T>& operator/=	(Vec2<T> &leftVec, const Vec2<T> &rightVec)
{	leftVec.x /= rightVec.x;
	leftVec.y /= rightVec.y;
	return leftVec;
}


//Other operations not implementable with operator overloading
template<typename T> Vec2<T>& normalize(const Vec2<T> &leftVec)
{
	return leftVec * (1.0 / lenght(leftVec));
}


template<typename T> Vec2<T> complexMultiply(const Vec2<T> &leftVec, const Vec2<T> &rightVec)
{
	return Vec2<T>(leftVec.x * rightVec.x - leftVec.y * rightVec.y,
					leftVec.x * rightVec.y + leftVec.y * rightVec.x);
}

template<typename T> T dot(const Vec2<T> &leftVec, const Vec2<T> &rightVec)
{
	return leftVec.x * rightVec.x + leftVec.y * rightVec.y;
}

template<typename T> T cross(const Vec2<T> &leftVec, const Vec2<T> &rightVec)
{
	return leftVec.x * rightVec.y - leftVec.y * rightVec.x;
}

template<typename T> T length(const Vec2<T> &leftVec)
{
	return sqrt(leftVec.x * leftVec.x + leftVec.y * leftVec.y);
}

template<typename T> T lengthSq(const Vec2<T> &leftVec)
{
	return (leftVec.x * leftVec.x + leftVec.y * leftVec.y);
}

template<typename T> Vec2<T> normalLeft(const Vec2<T> &leftVec)
{
	return Vec2<T>(leftVec.y, -leftVec.x);
}

template<typename T> Vec2<T> normalRight(const Vec2<T> &leftVec)
{
	return Vec2<T>(-leftVec.y, leftVec.x);
}

template<typename T> T scalarProjection(const Vec2<T> &leftVec, const Vec2<T> &rightVec)
{
	return dot(leftVec, rightVec) / length(rightVec);
}


template<typename T> Vec2<T> vectorProjection(const Vec2<T> &leftVec, const Vec2<T> &rightVec)
{
	Vec2<T> retVec = rightVec;
	retVec *= (dot(leftVec, rightVec) / lengthSq(rightVec));
	return retVec;
}


